﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using Eb;

namespace Es
{
    public class ZkConnection
    {
        //---------------------------------------------------------------------
        private static readonly int DEFAULT_SESSION_TIMEOUT = 3000000;
        private IntPtr mZookeeper = new IntPtr((long)0);
        private string mServer;
        private int mSessionTimeOut;

        //---------------------------------------------------------------------
        public ZkConnection(String zkServers)
            : this(zkServers, DEFAULT_SESSION_TIMEOUT)
        {
        }

        //---------------------------------------------------------------------
        public ZkConnection(String zkServers, int sessionTimeOut)
        {
            mServer = zkServers;
            mSessionTimeOut = sessionTimeOut;
        }

        //---------------------------------------------------------------------
        public void connect(zookeeper.watcher_fn fn)
        {
            if (mZookeeper != IntPtr.Zero) return;

            mZookeeper = zookeeper.zookeeper_init(mServer, fn, mSessionTimeOut, IntPtr.Zero, IntPtr.Zero, 0);
            if (mZookeeper == IntPtr.Zero)
            {
                EbLog.Error("CZkConnection connect failed , " + mServer);
            }
        }

        //---------------------------------------------------------------------
        public void close()
        {
            if (mZookeeper != IntPtr.Zero)
            {
                zookeeper.zookeeper_close(mZookeeper);
                mZookeeper = IntPtr.Zero;
            }
        }

        //---------------------------------------------------------------------
        //mode : ZK_CONST.ZOO_EPHEMERAL , ZK_CONST.ZOO_SEQUENCE
        public int acreate(string path, string data, int mode, zookeeper.string_completion_t handler, int id = 0)
        {
            if (data == null) data = "";

            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
            Marshal.WriteInt32(idPtr, id);
            int rtCode = zookeeper.zoo_acreate(mZookeeper, path, data, data.Length,
                           ZK_CONST.ZOO_OPEN_ACL_UNSAFE, mode, handler, idPtr);
            return rtCode;
        }

        //---------------------------------------------------------------------
        public int adelete(string path, zookeeper.void_completion_t handler, int id = 0)
        {
            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
            Marshal.WriteInt32(idPtr, id);
            //EbLog.Note("adelete begin :" + path);

            int rtCode = zookeeper.zoo_adelete(mZookeeper, path, -1, handler, idPtr);
            //EbLog.Note("adelete end :" + path);
            return rtCode;
        }

        //---------------------------------------------------------------------
        public int aexists(string path, bool watch, zookeeper.stat_completion_t handler, int id = 0)
        {
            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
            Marshal.WriteInt32(idPtr, id);
            //EbLog.Note("aexists begin :" + path);

            int rtCode = zookeeper.zoo_aexists(mZookeeper, path,
                    watch ? ZK_CONST.ADD_WATCH : ZK_CONST.NOT_WATCH, handler, idPtr);
            //EbLog.Note("aexists end :" + path);
            return rtCode;
        }

        //---------------------------------------------------------------------
        public int agetChildren(string path, bool watch, zookeeper.strings_completion_t handler, int id = 0)
        {
            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
            Marshal.WriteInt32(idPtr, id);

            int rtCode = zookeeper.zoo_aget_children(mZookeeper, path,
                watch ? ZK_CONST.ADD_WATCH : ZK_CONST.NOT_WATCH, handler, idPtr);
            return rtCode;
        }

        //---------------------------------------------------------------------
        public int areadData(string path, bool watch, zookeeper.data_completion_t handler, int id = 0)
        {
            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
            Marshal.WriteInt32(idPtr, id);
            int rtCode = zookeeper.zoo_aget(mZookeeper, path,
                watch ? ZK_CONST.ADD_WATCH : ZK_CONST.NOT_WATCH, handler, idPtr);
            return rtCode;
        }

        //---------------------------------------------------------------------
        public int awriteData(string path, string data, zookeeper.stat_completion_t handler, int id = 0)
        {
            IntPtr idPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(IntPtr)));
            Marshal.WriteInt32(idPtr, id);
            int rtCode = zookeeper.zoo_aset(mZookeeper, path, data, data.Length, -1, handler, idPtr);
            return rtCode;
        }

        //---------------------------------------------------------------------
        public static void setlogdir(string path, int lvl)
        {
            zookeeper.zoo_set_debug_level(lvl);
            zookeeper.zoo_set_log_dir(path);
        }

        //---------------------------------------------------------------------
        public int getState()
        {
            return mZookeeper != IntPtr.Zero ? zookeeper.zoo_state(mZookeeper) : 0;
        }

        //---------------------------------------------------------------------
        public string getServer()
        {
            return mServer;
        }

        //---------------------------------------------------------------------
        public int screate(string path, string data, int flags, out string new_path)
        {

            int rtCode = zookeeper.zoo_create(mZookeeper, path, data, data.Length,
                ZK_CONST.ZOO_OPEN_ACL_UNSAFE, flags, ZK_CONST.STR_BUFFER, ZK_CONST.ZOO_STR_BUF_LEN);
            if (rtCode == 0)
            {
                new_path = zookeeper.getString(ZK_CONST.STR_BUFFER);
            }
            else
            {
                new_path = "";
            }
            return rtCode;
        }

        //---------------------------------------------------------------------
        public int sdelete(string path)
        {
            return zookeeper.zoo_delete(mZookeeper, path, -1);
        }

        //---------------------------------------------------------------------
        public string sread(string path, bool watch)
        {
            string data = "";
            int rtCode = zookeeper.zoo_get(mZookeeper, path, watch ?
                ZK_CONST.ADD_WATCH : ZK_CONST.NOT_WATCH, ZK_CONST.STR_BUFFER, ZK_CONST.INT_BUFFER, IntPtr.Zero);
            if (rtCode == 0)
            {
                data = zookeeper.getString2(ZK_CONST.STR_BUFFER, ZK_CONST.INT_BUFFER);
            }
            return data;
        }

        //---------------------------------------------------------------------
        public int swrite(string path, string buffer)
        {
            int rtCode = zookeeper.zoo_set(mZookeeper, path, buffer, buffer.Length, -1);
            return rtCode;
        }

        //---------------------------------------------------------------------
        public string[] sget_children(string path, bool watch)
        {
            string[] rtVec = new string[] { };
            int rtCode = zookeeper.zoo_get_children(mZookeeper, path, watch ?
                ZK_CONST.ADD_WATCH : ZK_CONST.NOT_WATCH, ZK_CONST.STRS_BUFFER);
            if (rtCode == 0)
            {
                rtVec = zookeeper.getString_vector(ZK_CONST.STRS_BUFFER);
            }
            return rtVec;
        }

        //---------------------------------------------------------------------
        public bool sexists(string path, bool watch)
        {
            return zookeeper.zoo_exists(mZookeeper, path, watch ?
                ZK_CONST.ADD_WATCH : ZK_CONST.NOT_WATCH, IntPtr.Zero) == 0;
        }
    }
}
